#pragma once

#include<iostream>
#include<pthread.h>
#include<queue>

const int gmaxcap = 100;

template<class T>
class Blockqueue
{
    public:
        Blockqueue(const int& maxcap = gmaxcap):_maxcap(maxcap)
        {
            pthread_mutex_init(&_mutex,nullptr);
            pthread_cond_init(&_pcond,nullptr);
            pthread_cond_init(&_ccond,nullptr);
        }

        void push(const T& in)
        {
            pthread_mutex_lock(&_mutex);
            //必须用while来判断,不能用if
            while(isfull()) 
                pthread_cond_wait(&_pcond,&_mutex);
            //pthread_cond_wait在调用时，会以原子性的方式，将锁释放，然后将自己挂起
            //pthread_cond_wait在被唤醒返回时，会自动重新获取锁，并加锁
            _q.push(in);
            pthread_cond_signal(&_ccond);
            pthread_mutex_unlock(&_mutex);
        }

        void pop(T* out)
        {
            pthread_mutex_lock(&_mutex);
            while(isempty())
                pthread_cond_wait(&_ccond,&_mutex);
            *out = _q.front();
            _q.pop();
            pthread_cond_signal(&_pcond);
            pthread_mutex_unlock(&_mutex);
        }

        ~Blockqueue()
        {
            pthread_cond_destroy(&_ccond);
            pthread_cond_destroy(&_pcond);
            pthread_mutex_destroy(&_mutex);
        }
    private:
        bool isempty() {return _q.empty();}
        bool isfull() {return _q.size()==_maxcap;}
    private:
        std::queue<T> _q;
        int _maxcap;
        pthread_cond_t _pcond;
        pthread_cond_t _ccond;
        pthread_mutex_t _mutex;
};